<template>
  <div>
    <div class="charts">
      <ElCard>
        <template #header>
          <div class="header">
            <span class="title">内存监控</span>
            <ElButton link @click="() => (memoryCache = getMemory())">
              <ElIcon class="iconfont icon-shuaxin"></ElIcon>
            </ElButton>
          </div>
        </template>
        <div class="charts-container">
          <ElProgress
            type="dashboard"
            :stroke-width="10"
            :width="150"
            :percentage="+memoryCache.usageRate"
          >
            <template #default="{ percentage }">
              <span class="percentage-value">{{ percentage }}%</span>
              <span class="percentage-label">使用率</span>
            </template>
          </ElProgress>
          <div class="norm">
            <div class="item">
              <span class="label">内存限制</span>
              <ElTag>{{ memoryCache.jsHeapSizeLimit }}</ElTag>
            </div>
            <div class="item">
              <span class="label">已分配</span>
              <ElTag type="warning">
                {{ memoryCache.totalJSHeapSize }}
              </ElTag>
            </div>
            <div class="item">
              <span class="label">实际使用</span>
              <ElTag type="success">
                {{ memoryCache.usedJSHeapSize }}
              </ElTag>
            </div>
          </div>
        </div>
      </ElCard>
      <ElCard>
        <template #header>
          <div class="header">
            <span class="title">Web Storage</span>
            <ElButton link @click="() => (webStorage = getWebStorageInfo())">
              <ElIcon class="iconfont icon-shuaxin"></ElIcon>
            </ElButton>
          </div>
        </template>
        <div class="charts-container">
          <ElProgress
            type="dashboard"
            :stroke-width="10"
            :width="150"
            :percentage="+webStorage.usageRate"
          >
            <template #default="{ percentage }">
              <span class="percentage-value">{{ percentage }}%</span>
              <span class="percentage-label">已使用</span>
            </template>
          </ElProgress>
          <div class="norm">
            <div class="item">
              <span class="label">剩余空间</span>
              <ElTag>
                {{ webStorage.remainingSize }}
              </ElTag>
            </div>
            <div class="item">
              <span class="label">LocalStorage</span>
              <ElTag type="warning">
                {{ webStorage.localSize }} / ({{ webStorage.localCount }}个)
              </ElTag>
            </div>
            <div class="item">
              <span class="label">SessionStorage</span>
              <ElTag type="success">
                {{ webStorage.sessionSize || "0 B" }} / ({{
                  webStorage.sessionCount
                }}个)
              </ElTag>
            </div>
          </div>
        </div>
      </ElCard>
      <ElCard>
        <template #header>
          <div class="header">
            <span class="title">Cookies</span>
            <ElButton link @click="getCookies">
              <ElIcon class="iconfont icon-shuaxin"></ElIcon>
            </ElButton>
          </div>
        </template>
        <div class="charts-container">
          <ElProgress
            type="dashboard"
            :stroke-width="10"
            :width="150"
            :percentage="+cookieStorage.usageRate || 0"
          >
            <template #default="{ percentage }">
              <span class="percentage-value">{{ percentage }}%</span>
              <span class="percentage-label">已使用</span>
            </template>
          </ElProgress>
          <div class="norm">
            <div class="item">
              <span class="label">剩余空间</span>
              <ElTag>
                {{ cookieStorage.remainingSize }}
              </ElTag>
            </div>
            <div class="item">
              <span class="label">大小</span>
              <ElTag type="warning">{{ cookieStorage.size }}</ElTag>
            </div>
            <div class="item">
              <span class="label">个数</span>
              <ElTag type="success">{{ cookieStorage.count }}个</ElTag>
            </div>
          </div>
        </div>
      </ElCard>
    </div>
    <div class="storage_content">
      <SearchTable
        :searchFields="['key']"
        :data="allStorage"
        :columns="columns"
      />
    </div>
  </div>
</template>

<script setup>
import SearchTable from "@/components/Basic/SearchTable/index.vue";
import { getFileSize } from "@/utils";
import { ref } from "vue";
const allStorage = ref([]);
const memoryCache = ref(getMemory());
const webStorage = ref(getWebStorageInfo());
const cookieStorage = ref({});
const columns = ref([
  {
    label: "Key",
    prop: "key",
    showOverflowTooltip: true,
  },
  {
    label: "Value",
    prop: "value",
    showOverflowTooltip: true,
  },
  {
    label: "Size",
    prop: "size",
    sortable: true,
    formatter: (row) => getFileSize(row.size),
  },
  {
    label: "Type",
    prop: "type",
    tag: true,
    filters: [
      { text: "SessionStorage", value: "sessionStorage" },
      { text: "LocalStorage", value: "localStorage" },
      { text: "Cookie", value: "cookie" },
    ],
    filterMethod: (value, row, column) => row.type === value,
  },
]);

function getMemory() {
  const mem = window.performance.memory;
  return {
    jsHeapSizeLimit: getFileSize(mem.jsHeapSizeLimit), // 浏览器内存限制
    totalJSHeapSize: getFileSize(mem.totalJSHeapSize), // 总内存使用量
    usedJSHeapSize: getFileSize(mem.usedJSHeapSize), // 已使用的内存量
    usageRate: ((mem.usedJSHeapSize / mem.totalJSHeapSize) * 100).toFixed(2),
  };
}
function getWebStorageInfo() {
  const localSize = calculateWebStorageSize(window.localStorage);
  const sessionSize = calculateWebStorageSize(window.sessionStorage);
  const totalSize = 5 * 1024 * 1024; // 10MB 浏览器总存储空间(默认)
  const remainingSize = totalSize - localSize - sessionSize;
  return {
    totalSize,
    remainingSize: getFileSize(remainingSize),
    sessionCount: window.sessionStorage.length,
    sessionSize: getFileSize(sessionSize),
    localCount: window.localStorage.length,
    localSize: getFileSize(localSize),
    usageRate: (((sessionSize + localSize) / totalSize) * 100).toFixed(2),
  };
}
// localStorage/sessionStorage
function calculateWebStorageSize(storage) {
  let total = 0;
  for (let i = 0; i < storage.length; i++) {
    const key = storage.key(i);
    const value = decodeURIComponent(storage.getItem(key));
    const type =
      storage === window.sessionStorage ? "sessionStorage" : "localStorage";
    const encoder = new TextEncoder();
    const uint8Array = encoder.encode(key + value);
    const size = uint8Array.byteLength;
    const s = allStorage.value.find((s) => s.key === key && s.type === type);
    const data = {
      key,
      value,
      size,
      type,
    };
    if (s) {
      Object.assign(s, data);
    } else {
      allStorage.value.push(data);
    }
    // UTF8 字符1个字节 汉字 3 字节  UTF16 字符汉字都为2字节
    total += size;
  }
  return total; // 返回字节数
}

async function getCookies() {
  // allStorage.value = [];
  const allCookies = await window.cookieStore.getAll();
  const totalSize = 5 * 1024 * 1024;
  let total = 0;
  for (const c of allCookies) {
    const key = c.name;
    const value = decodeURIComponent(c.value);
    const encoder = new TextEncoder();
    const uint8Array = encoder.encode(key + value);
    const size = uint8Array.byteLength;
    const s = allStorage.value.find((s) => s.key === key);
    const data = {
      key,
      value,
      size,
      type: "cookie",
    };
    if (s) {
      Object.assign(s, data);
    } else {
      allStorage.value.push(data);
    }
    // UTF8 字符1个字节 汉字 3 字节  UTF16 字符汉字都为2字节
    total += size;
  }
  cookieStorage.value = {
    totalSize,
    remainingSize: getFileSize(totalSize - total),
    count: allCookies.length,
    size: getFileSize(total),
    usageRate: ((total / totalSize) * 100).toFixed(2),
  };
}
getCookies();
</script>

<style scoped>
.charts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 15px;
}
.storage_content {
  margin-top: 15px;
}
.charts .title {
  font-weight: bold;
}
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.charts-container {
  display: flex;
  align-items: center;
  flex-direction: column;
  justify-content: center;
}
.charts-container .norm {
  width: 100%;
}
.charts-container .norm .item {
  display: flex;
  justify-content: space-between;
  margin: 5px 0;
}

.norm .item .label {
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--text-secondary);
}
.charts .percentage-value {
  display: block;
  margin-top: 10px;
  font-size: 28px;
}
.charts .percentage-label {
  display: block;
  margin-top: 10px;
  font-size: 0.8rem;
}
</style>
